home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 096 / calls2.arc / CALLS.C next >
Encoding:
C/C++ Source or Header  |  1985-12-08  |  15.6 KB  |  621 lines

  1. /*
  2.  * CALLS.C
  3.  *     prints a paragraphed list of function calls
  4.  *     that occur in a body of C source code.
  5.  *
  6.  * Author: M.M. Taylor, DCIEM, Toronto, Canada.
  7.  * Modified for IBM-PC DOS 2.1, 02/Dec/85, Robert E. Sawyer, Torrance, CA.
  8.  *     (DeSmet C v2.4)
  9.  */
  10.  
  11. #include <stdio.h>
  12.  
  13. #ifdef  DESMET
  14. #else
  15. #include <ctype.h>
  16. #endif
  17.  
  18. #define ATOMLENGTH 20
  19. #define MAXNAME 500
  20. #define MAXINST 4000
  21. #define MAXDEPTH 25
  22. #define MAXSEEN 100
  23. #define PAPERWIDTH 80  
  24. #define TAB "    "
  25. #define TABSIZE 4
  26.  
  27.  
  28. int bracket, linect, terse, ntabs;
  29. char aseen [MAXSEEN][ATOMLENGTH];
  30.  
  31. /* if lastchar==0, getch gets next character, else getch gets lastchar */
  32. int lastchar;
  33. char *sysword [ ] = 
  34.     {
  35.     "if",
  36.     "while",
  37.     "for",
  38.     "return",
  39.     "switch",
  40.     0
  41.     };
  42.  
  43. struct rname
  44.     {
  45.     char namer[ATOMLENGTH];
  46.     int rnamecalled;
  47.     int rnameout;
  48.     struct rinst *dlistp;
  49.     } namelist[MAXNAME];
  50.  
  51. struct rinst
  52.     {
  53.     struct rname *namep;
  54.     struct rinst *calls;
  55.     struct rinst *calledby;
  56.     } dlist[MAXINST];
  57.  
  58. struct rname *activelist[MAXDEPTH];
  59. int activep = 0;
  60. struct rinst *frp;
  61.  
  62. FILE *fin, *fopen();
  63.  
  64. main(argc,argv)
  65.     int argc;
  66.     char *argv[];
  67.     {
  68.     int gf, i, ok;
  69.     char atom[ATOMLENGTH];
  70.     char *startfunc;
  71.     struct rname *startp, *lookfor();
  72.     struct rinst *curproc, *initfree(), *newproc(), *add2call();
  73.  
  74.     bracket=0;
  75.     terse=1;
  76.     lastchar = 0;
  77.     aseen[0][0] = 0;
  78.     startfunc = "main" ;
  79.     frp = dlist;
  80.     initfree();
  81.     for (i = 0; i < MAXDEPTH ; i++ ) activelist[i] = 0 ;
  82.     activep = 0;
  83.     ntabs = (PAPERWIDTH - 20)/TABSIZE;
  84.  
  85.     if (argc < 2)
  86.         usage();
  87.     else if ((fin = fopen(argv[1],"r")) == NULL)
  88.         {
  89.         printf("\nCan't open %s\n",argv[1]);
  90.         usage();
  91.         }
  92.            
  93.     /*  get arguments and flags*/
  94.     for (i = 2; i<argc && (argv[i][0]=='-' || argv[i][0]=='?'); i++)
  95.         {
  96.         if (match(argv[i],"-v"))
  97.             terse=0;
  98.         else if (match(argv[i],"-w"))
  99.             ntabs = (atoi(argv[++i])-20)/TABSIZE;
  100.         else
  101.             usage();
  102.         }
  103.     ok = 1;
  104.     while ((gf = getfunc(atom)) != -1 && ok ){
  105.         if (gf) ok = (int)add2call(atom,curproc);
  106.         else ok = (int)(curproc = newproc(atom));
  107.         }
  108.     if (i<argc)
  109.         {
  110.         do
  111.             {
  112.             startfunc = argv[i];
  113.             if (startp = (lookfor(startfunc)))
  114.                 {
  115.                 output (startp,0);
  116.                 printf ("\n\n");
  117.                 }
  118.             else printf ("*** error *** %s not found\n",startfunc);
  119.             } while (++i<argc);
  120.         }
  121.     else
  122.         {
  123.         for (startp=namelist; startp->namer[0] ; startp++)
  124.             {
  125.             if (!startp->rnamecalled)
  126.                 {
  127.                 output (startp,0);
  128.                 printf ("\n\n");
  129.                 }
  130.             }
  131.         }
  132.     fclose(fin);
  133.     }
  134.  
  135. /* return name of a function. value 0 == definition, 1 == called */
  136. getfunc(atom)
  137.     char atom[];
  138.     {
  139.     int c;
  140.     int ss;
  141.     for(;;)
  142.         {
  143.         c = getch();
  144.         if (isalpha(c))
  145.             {
  146.             lastchar=c;
  147.             scan(atom);
  148.             continue;
  149.             }
  150.         else
  151.             {
  152.             switch(c)
  153.                 {
  154.                 case '\t':
  155.                 case ' ':
  156.                     continue;
  157.                 case '\n':
  158.                    if ((c= getch())=='#')
  159.                         while ((c= getch()) != '\n')
  160.                             ;
  161.                     lastchar = c;
  162.                     continue;
  163.                 case '\'':
  164.                     atom[0]='\0';
  165.                     while ((c= getch()) != '\'')
  166.                         if (c == '\\') 
  167.                             getch();
  168.                         continue;
  169.                 case '\"':
  170.                     while (( c = getch()) != '\"')
  171.                         if (c=='\\') 
  172.                             getch();
  173.                     continue;
  174.                 case '\\':
  175.                     atom[0] = '\0';
  176.                     getch();
  177.                     continue;
  178.                 case '{':
  179.                     bracket++;
  180.                     atom[0]='\0';
  181.                     continue;
  182.                 case '}':
  183.                     --bracket;
  184.                     if (bracket < 0)
  185.                         printf ("bracket underflow");
  186.                     atom[0]='\0';
  187.                     continue;
  188.                 case '(':
  189.                     if( ! atom[0] ) 
  190.                         continue;
  191.                     if (!checksys(atom)) 
  192.                         {
  193.                         if (!bracket)
  194.                             return (0);
  195.                         if ((ss=seen(atom))==-1)
  196.                             printf("aseen overflow");
  197.                         if (bracket && !ss) 
  198.                             return (1);
  199.                         }
  200.                     atom[0]='\0';
  201.                     continue;
  202.                 case ')':
  203.                     atom[0]='\0';
  204.                     continue;
  205.                 case EOF:
  206.                     return (-1);
  207.                 case '/':
  208.                     if (( c = getch())=='*')
  209.                         {
  210.                         for (;;)
  211.                             {
  212.                             while (getch() != '*')
  213.                                 ;
  214.                             if ((c = getch()) == '/')
  215.                                 break;
  216.                             lastchar = c;
  217.                             }
  218.                         continue;
  219.                         }
  220.                     else 
  221.                         {
  222.                         lastchar = c;
  223.                         continue;
  224.                         }
  225.                 case '*':
  226.                     atom [0] = '\0';
  227.                     continue;
  228.                 default:
  229.                     atom[0]='\0';
  230.                     continue;
  231.                 }
  232.             }
  233.         }
  234.     }
  235.  
  236. /* scan text until an atom that could be a function name is found */
  237. scan(atom)
  238.     char atom[];
  239.     {
  240.     char c;
  241.     int i;
  242.  
  243.     c = lastchar;
  244.     i = 0;
  245.     while( isalpha(c) || isdigit(c) || (c == '_') )
  246.         {
  247.         atom [i++] = (c=getch());
  248.         if (i == ATOMLENGTH ) 
  249.             break;
  250.         }
  251.     atom [i-1] = '\0';
  252.     while( isalpha(c) || isdigit(c) || (c == '_') ) 
  253.         c = getch();
  254.     lastchar= c;
  255.     return (1);
  256.     }
  257.  
  258. /* return value 1 if atom is a system keyword, else 0 */
  259. checksys(atom)
  260.     char atom[];
  261.     {
  262.     int i;
  263.  
  264.     for (i=0; sysword[i] ; i++)
  265.         if (match(atom,sysword[i])) 
  266.             return (1);
  267.         return (0);
  268.     }
  269.  
  270. /*** see if we have seen this function within this process ***/
  271.  
  272. seen(atom)
  273.     char *atom;
  274.     {
  275.     int i,j;
  276.  
  277.     for (i=0; aseen[i][0] && i < MAXSEEN ; i++)
  278.         {
  279.         if (match (atom, aseen[i])) 
  280.             return (1);
  281.         }
  282.     if (i >= MAXSEEN)
  283.         return (-1);
  284.     for (j=0; (aseen[i][j] = atom[j]) != '\0' && j < ATOMLENGTH ; j++) 
  285.         ;
  286.     aseen[i+1][0] = '\0';
  287.     return (0);
  288.     }
  289.  
  290. /* return 1 if strings match, else 0 */
  291. match(atom,name)
  292.     char name[];
  293.     char atom[];
  294.     {
  295.     register char *ap,*np;
  296.  
  297.     ap = atom;
  298.     np = name;
  299.     while (*ap==*np)
  300.         {
  301.         if (*ap== 0) 
  302.             return (1);
  303.         ap++; np++;
  304.         }
  305.     return (0);
  306.     }
  307.  
  308. /* get a character, but perhaps return previous one instead */
  309. getch()
  310.     {
  311.     int c;
  312.  
  313.     if( lastchar == 0 )
  314.         return (fgetc(fin));
  315.     c = lastchar;
  316.     lastchar = 0;
  317.     return (c);
  318.     }
  319.  
  320. /*
  321. when scanning the text each function instance is inserted into a
  322. linear list of names, using the rname structure, when it is first
  323. encountered. It is also inserted into the linked list using the rinst
  324. structure. The entry into the name list has a pointer to the defining
  325. instance in the linked list, and each entry in the linked list has
  326. a pointer back to the relevant name. Newproc makes an entry in the
  327. defining list, which is distinguished from the called list only because
  328. it has no calledby link (value=0). Add2proc enters into the called
  329. list, by inserting a link to the new instance in the calls pointer of
  330. the last entry (may be a defining instance, or a function called by
  331. that defining instance), and points back to the defining instance of
  332. the caller in its called-by pointer.
  333. */
  334.  
  335. struct rinst *
  336. newproc(name)
  337.     char name[];
  338.     {
  339.     struct rinst *install();
  340.     struct rname *place();
  341.  
  342.     aseen[0][0] = '\0';
  343.     return (install(place(name),(struct rinst *)0));
  344.     }
  345.  
  346. struct rinst *
  347. add2call(name,curp)
  348.     char name[];
  349.     struct rinst *curp;
  350.     {
  351.     struct rinst *install(),*ip;
  352.     struct rname *place(),*p;
  353.  
  354.     ip = install(p = place(name),curp);
  355.     if (p)
  356.         ++(p->rnamecalled);
  357.     return (ip);
  358.     }
  359.  
  360. /**
  361. place(name)  returns a pointer to the name on the namelist.
  362.         If the name was not there, it puts it at the end of the list.
  363.         If there was no room, it returns -1.
  364. **/
  365.  
  366. struct rname *
  367. place(name)
  368.     char name[];
  369.     {
  370.     int i,j;
  371.     struct rname *npt;
  372.  
  373.     for (i = 0 ; (npt = &namelist[i])->namer[0] && i<MAXNAME ; i++)
  374.         {
  375.         if (match(name,npt->namer))
  376.             return (npt);
  377.         if (i >= MAXNAME)
  378.             {
  379.             printf ("namelist overflow");
  380.             return ( (struct rname *) -1);
  381.             }
  382.         }
  383. /* name was not on list, so put it on */
  384.  
  385.     for (j=0 ; name[j]; j++)
  386.         npt->namer[j] = name[j];
  387.     npt->namer[j] = '\0';
  388.     (npt+1)->namer[0] = '\0';
  389.     npt->rnamecalled = 0;
  390.     npt->rnameout=0;
  391.     return (npt);
  392.     }
  393.  
  394. /**
  395. install(np,rp) puts a new instance of a function into the linked list.
  396. It puts a pointer (np) to its own name (returned by place) into its
  397. namepointer, a pointer to the calling routine (rp) into
  398. its called-by pointer, and zero into the calls pointer. It then
  399. puts a pointer to itself into the last function in the chain.
  400. **/
  401.  
  402. struct rinst *
  403. install(np,rp)
  404.     struct rname *np;
  405.     struct rinst *rp;
  406.     {
  407.     struct rinst *newp;
  408.     struct rinst *op;
  409.     struct rinst *getfree();
  410.  
  411.     if (!np)
  412.         return ( (struct rinst *) -1);
  413.     if ( !(newp = getfree())) 
  414.         return ( (struct rinst *) 0);
  415.     newp->namep = np;
  416.     newp->calls = 0;
  417.     if (rp)
  418.         {
  419.         op = rp;
  420.         while (op->calls)
  421.             op = op->calls;
  422.         newp->calledby = op->calledby;
  423.         op->calls = newp;
  424.         }
  425.     else 
  426.         {
  427.         newp->calledby = (struct rinst *) np;
  428.         np->dlistp = newp;
  429.         }
  430.     return (newp);
  431.     }
  432.  
  433. /*
  434. getfree returns a pointer to the next free instance block on the list
  435. */
  436.  
  437. struct rinst *
  438. getfree()
  439.     {
  440.     struct rinst *ret;
  441.  
  442.     ret=frp;
  443.     if (!ret)
  444.         printf ("out of instance blocks\n");
  445.     frp=frp->calls;
  446.     return(ret);
  447.     }
  448.  
  449. /*
  450. initfree makes a linked list of instance blocks, and returns a pointer
  451. to the first one. it is called only once, at the beginning of the programme.
  452. */
  453.  
  454. struct rinst *
  455. initfree()
  456.     {
  457.     int i;
  458.  
  459.     for (i = 0 ; i < MAXINST-2 ; i++) 
  460.         {
  461.         frp->namep = 0;
  462.         frp->calls = frp+1;
  463.         (frp+1)->calledby = frp;
  464.         frp++;
  465.         }
  466.     frp->namep=0;
  467.     frp->calls = 0;
  468.     frp= dlist;
  469.     return(dlist);
  470.     }
  471.  
  472. /********
  473. output is a recursive routine which is supposed to print one tab for each
  474. level of recursion, then the name of the function called, followed by the
  475. next function called by the same higher level routine. In doing this, it
  476. calls itself to output the name of the first function called by the
  477. function whose name it is outputting. It maintains an active list of
  478. functions currently being output by the different levels of recursion,
  479. and if it finds itself asked to output one which is already active,
  480. it terminates, marking that call with a * .
  481. *********/
  482.  
  483. output(func,tabc)
  484.     struct rname *func;
  485.     int tabc;
  486.     {
  487.     struct rinst *nextp;
  488.     int i, tabd, tabstar, tflag;
  489.  
  490.     ++linect;
  491.     printf ("\n%d  ",linect);
  492.     if (!(makeactive(func)))
  493.         printf ("*"); /* calls nested too deep */
  494.     else 
  495.         {
  496.         tabstar= 0;
  497.         tabd = tabc;
  498.         for (;tabd >ntabs; tabstar++) 
  499.             tabd = tabd-ntabs;
  500.         for (i = 0 ; i < tabstar ; i++ ) 
  501.             printf ("<");
  502.         printf (" ");
  503.         for (i = 0 ; i < tabd ; i++ )
  504.             printf ("%s",TAB);
  505.         if (active(func))
  506.             printf ("^ %s ^",func->namer); /* recursive call */
  507.         else 
  508.             {
  509.             if (func->dlistp)
  510.                 {
  511.                 printf ("%s", func->namer);
  512.                 nextp = func->dlistp->calls;
  513.                 if (!terse || !func->rnameout) 
  514.                     {
  515.                     ++tabc;
  516.                     if (!func->rnameout) 
  517.                         func->rnameout = linect;
  518.                     if (tabc > ntabs && tabc%ntabs==1 && nextp)
  519.                         {
  520.                         printf("\n- - - - - - - - - - - - - - - - - - - ");
  521.                         printf("- - - - - - - - - - - - - - -");
  522.                         tflag = 1;
  523.                         }
  524.                     else
  525.                         tflag = 0;
  526.                     for (;nextp; nextp = nextp->calls)
  527.                         output (nextp->namep, tabc);
  528.                     if (tflag)
  529.                         {
  530.                         printf("\n- - - - - - - - - - - - - - - - - - - ");
  531.                         printf("- - - - - - - - - - - - - - -");
  532.                         tflag = 0;
  533.                         }
  534.                     }
  535.                 else if (nextp)
  536.                     printf (" ... [see line %d]", func->rnameout);
  537.                 }
  538.             else 
  539.                 printf ("%s [ext]",func->namer); /* library or external call */
  540.             }
  541.         backup();
  542.         }
  543.     return;
  544.     }
  545.  
  546. /*
  547. makeactive simply puts a pointer to the nameblock into a stack with
  548. maximum depth MAXDEPTH. the error return only happens for stack overflow.
  549. */
  550.  
  551. makeactive(func)
  552.     struct rname *func;
  553.     {
  554.     if (activep < MAXDEPTH)
  555.         {
  556.         activelist[activep] = func;
  557.         activep++;
  558.         return (1);
  559.         }
  560.     else
  561.         return (0);
  562.     }
  563.  
  564. /*
  565. backup removes an item from the active stack
  566. */
  567.  
  568. backup()
  569.     {
  570.     if (activep)
  571.         {
  572.         activelist [activep--] = 0;
  573.         return (1);
  574.         }
  575.     else return (-1);
  576.     }
  577.  
  578. /*
  579. active checks whether the pointer which is its argument has already
  580. occurred on the active list, and returns 1 if so.
  581. */
  582.  
  583. active(func)
  584.     struct rname *func;
  585.     {
  586.     int i;
  587.  
  588.     for (i = 0; i < activep-1 ; i++)
  589.         if (func == activelist[i])
  590.             return (1);
  591.     return (0);
  592.     }
  593.  
  594. /* lookup(name) accepts a pointer to a name and sees if the name is on the
  595. namelist. If so, it returns a pointer to the nameblock. Otherwise
  596. returns zero.
  597. */
  598.  
  599. struct rname *
  600. lookfor(name)
  601.     char *name;
  602.     {
  603.     struct rname *np;
  604.  
  605.     for (np = namelist; np->namer[0] ; np++)
  606.         if (match(name, np->namer)) 
  607.             return (np);
  608.     return (0);
  609.     }
  610.  
  611. usage()
  612.     {
  613.     printf("\nCALLS reads a C source program,\n");
  614.     printf("and writes the function-call structure to stdout.\n");
  615.     printf("\nUsage:  CALLS fromfile [>tofile] [-v] [-w nn] [fun1 ...]\n");
  616.     printf("\n-v          verbose form (default is terse)\n");
  617.     printf("-w nn       paper width  (default is 80)\n");
  618.     printf("fun1 ...    names of functions to start at (default is main)\n\n");
  619.     exit();
  620.     }
  621.